package com.icw.resource.workflow.module.mgr;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.icw.configuration.ConstSettings;
import com.icw.decoupling.impl.module.RestfulMgrImpl;
import com.icw.decoupling.defi.proxy.GenericSrvProxy;
import com.icw.decoupling.defi.tool.DataExchange;
import com.icw.resource.workflow.entity.WorkFlowInstance;
import com.icw.resource.workflow.entity.WorkFlowVariable;
import com.icw.resource.workflow.entity.WorkStateDefinition;
import com.icw.resource.workflow.entity.WorkStateInstance;
import com.icw.resource.workflow.entity.WorkStatePropDefinition;
import com.icw.utility.BeanCtxUtils;
import com.icw.utility.IcwUtils;
import com.icw.utility.PoEntityHelper;
import com.icw.utility.PropertyPathHelper;
import com.icw.utility.WorkFlowHelper;
import com.icw.basis.BasePoEntity;

public class WorkStateInstanceRestfulMgr extends RestfulMgrImpl<WorkStateInstance> {

	@Override
	public void post(Map<String, Object> params, HttpServletRequest request, HttpServletResponse response, Map<String, Object> data) throws Exception {
		// 1. prepare sources for filling
		WorkStateDefinition stateDefinition = srv().one(WorkStateDefinition.class, (String) PoEntityHelper.readValueByProperty(params, "stateDefinition.id"));
		WorkFlowInstance flowInstance = srv().one(WorkFlowInstance.class, (String) PoEntityHelper.readValueByProperty(params, "flowInstance.id"));
		// 2. filling
		PoEntityHelper.writeValueByProperty(params, "activityInstances", PoEntityHelper.transFromRoot(params, stateDefinition, "root[].activityDefinition.id=activityDefinitions[].id", "root[].stateInstance=${}").get("root"));
		PoEntityHelper.writeValueByProperty(params, "statePropInstances", mergeStatePropInstancesByStatePropDefinition(flowInstance, stateDefinition));
		super.post(params, request, response, data);
	}

	private Object[] mergeStatePropInstancesByStatePropDefinition(WorkFlowInstance flowInstance, WorkStateDefinition stateDefinition) throws Exception {
		Object[] statePropDefinitions = PoEntityHelper.loadMany(WorkStateDefinition.class, stateDefinition.getId(), "statePropDefinitions");
		Map<String, Object> realVariableMap = WorkFlowHelper.findRealVariableMap(WorkFlowHelper.findWorkVariableMap(flowInstance));
		for (int i = 0; i < statePropDefinitions.length; i++) {
			WorkStatePropDefinition statePropDefinition = WorkStatePropDefinition.class.cast(statePropDefinitions[i]);
			statePropDefinitions[i] = IcwUtils.mapObject("property", statePropDefinition.getProperty(), "previousValue", PoEntityHelper.parseJSEL(realVariableMap, statePropDefinition.getProperty()));
			executeStatePropDefinition(flowInstance, statePropDefinition);
		}
		return statePropDefinitions;
	}

	@SuppressWarnings("unchecked")
	private void executeStatePropDefinition(WorkFlowInstance flowInstance, WorkStatePropDefinition statePropDefinition) throws Exception {
		Map<String, WorkFlowVariable> workVariableMap = WorkFlowHelper.findWorkVariableMap(flowInstance);
		Map<String, Object> realVariableMap = WorkFlowHelper.findRealVariableMap(workVariableMap);
		String[] properties = PoEntityHelper.splitProperties(statePropDefinition.getProperty());
		String rootProperty = properties[0];
		String ending = properties[properties.length - 1];
		Object container = PoEntityHelper.readValueByProperty(realVariableMap, PropertyPathHelper.popAndReturn(statePropDefinition.getProperty()));
		if (container == null) {
			throw new Exception("Value of property \"" + PropertyPathHelper.popAndReturn(statePropDefinition.getProperty()) + "\" does not exist.");
		} else {
			Object newValue = PoEntityHelper.parseJSEL(realVariableMap, (String) PoEntityHelper.readValueByProperty(statePropDefinition, "initialValue"));
			WorkFlowVariable workVariable = workVariableMap.get(rootProperty);
			if (properties.length == 1) {
				String entityType = workVariable != null ? workVariable.getEntityType() : statePropDefinition.getEntityType();
				Object realVariable = IcwUtils.mgrSave(ConstSettings.URsrcEntityMap.get(entityType), Map.class.cast(newValue));
				Map<String, Object> newWorkVariable = IcwUtils.mapObject();
				newWorkVariable.put("id", PoEntityHelper.readValueByProperty(workVariable, "id"));
				newWorkVariable.put("property", rootProperty);
				newWorkVariable.put("entityType", entityType);
				newWorkVariable.put("identity", PoEntityHelper.readValueByProperty(realVariable, "id"));
				newWorkVariable.put("flowInstance.id", flowInstance.getId());
				IcwUtils.mgrSave(WorkFlowVariable.class, newWorkVariable);
			} else {
				PoEntityHelper.readValueByProperty(IcwUtils.mgrSave((Class<? extends BasePoEntity>) container.getClass(), IcwUtils.mapObject("id", PoEntityHelper.readValueByProperty(container, "id"), ending, newValue)), ending);
			}
		}
	}

	public static GenericSrvProxy srv() {
		return BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
	}

	public static DataExchange de() {
		return BeanCtxUtils.getBeanByType(DataExchange.class);
	}
}
